<?php

namespace App\Custom\Map;

use GuzzleHttp\Client;

class Main
{
    const API = "https://apis.map.qq.com/ws/";
    const GEO_CODER_URL = self::API . "geocoder/v1/";
    const SEARCH_URL = self::API . "place/v1/search/";
    const SUGGESTION_URL = self::API . "place/v1/suggestion/";
    const CONVERT_URL = self::API . "coord/v1/translate";
    const DRIVE_DISTANCE = self::API . "distance/v1/";
    const MATRIX_DRIVE_DISTANCE = self::API . 'distance/v1/matrix/';

    /**
     * @var Client
     */
    private $client;

    public function __construct()
    {
        $this->client = new Client();
    }


    /**
     * 地址转换为坐标
     * @param       $address
     * @param array $options
     * @return mixed
     */
    public function addressToGeo($address, $options = [])
    {
        $options['address'] = $address;
        $ret = $this->httpGet(self::GEO_CODER_URL, $options);

        return $ret['result'];
    }

    /**
     * 搜索指定坐标周边关键字的地点
     * @param       $keyword
     * @param       $nearby (数组:[lat,lng,半径/米])
     * @param int   $page
     * @param array $options
     * @return mixed
     */
    public function searchAround($keyword, $nearby, $page = 1, $options = [])
    {
        $options['keyword'] = $keyword;
        $options['page_index'] = $page;
        $options['boundary'] = "nearby({$nearby[0]},{$nearby[1]},{$nearby[2]})";

        $options['orderby'] = '_distance';
        $options['page_size'] = 20;

        $ret = $this->httpGet(self::SEARCH_URL, $options);

        return $ret['data'];
    }

    /**
     *
     * @param       $keyword
     * @param int   $page
     * @param array $options
     * @return mixed
     */
    public function suggestion($keyword, $page = 1, $options = [])
    {
        $options['keyword'] = $keyword;
        $options['page_index'] = $page;

        $options['policy'] = 0;
        $options['address_format'] = 'long';
        $options['page_size'] = 20;

        $ret = $this->httpGet(self::SUGGESTION_URL, $options);

        return $ret['data'];
    }

    /**
     * 坐标解析地址并且返回附近POI列表
     * @param array $location [lat,lng]
     * @param int   $page
     * @param array $options
     * @return mixed
     */
    public function getPoi($location, $page = 1, $options = [])
    {
        $options['location'] = join($location, ',');
        $options['get_poi'] = isset($options['get_poi']) ? $options['get_poi'] : 1;

        // POI的配置
        $options['poi_options'] = "radius=1500;page_index={$page};page_size=5";

        $ret = $this->httpGet(self::GEO_CODER_URL, $options);

        // 显示指定的poi信息和附近POI列表
        $result['current'] = ['title' => $ret['result']['formatted_addresses']['recommend'], 'address' => $ret['result']['address'], 'ad_info' => $ret['result']['ad_info']];
        $result['pois'] = $ret['result']['pois'];

        foreach ($result['pois'] as &$item) {
            $item['province'] = $item['ad_info']['province'];
            $item['city'] = $item['ad_info']['city'];
            $item['district'] = $item['ad_info']['district'];
        }

        return $result;
    }

    /**
     * 坐标转换
     * @param array $location [lat, lng]
     * @param       $type
     * @return array
     */
    public function covertLocation($location, $type = 1)
    {
        $params['locations'] = join($location, ',');
        $params['type'] = $type;

        $ret = $this->httpGet(self::CONVERT_URL, $params);

        $locations = $ret['locations'];

        return [$locations[0]['lat'], $locations[0]['lng']];
    }

    /**
     * 计算起点坐标与终点坐标之间的距离
     * @param [array] $from 起点坐标数组格式["lat,lng","lat,lng"]...
     * @param [array] $to 终点坐标数组格式["lat,lng","lat,lng"]...
     * 起点与终点其中一个可以多为坐标
     * @return mixed
     */
    public function driveDistance($from, $to)
    {
        $options['from'] = implode(";", $from);
        $options['to'] = implode(";", $to);
        $ret = $this->httpGet(self::DRIVE_DISTANCE, $options);

        $data = [];
        foreach ($ret['result']['elements'] as $item) {
            $data[] = ["distance" => $item["distance"], "duration" => $item["duration"]];
        }

        return $data;
    }

    /**
     * 计算多对多起点坐标与终点坐标之间的距离
     * @param [array] $from 起点坐标数组格式["lat,lng","lat,lng"]...
     * @param [array] $to 终点坐标数组格式["lat,lng","lat,lng"]...
     * 起点与终点多对多
     * @return mixed
     */
    public function matrixDriveDistance($from, $to)
    {
        $options['from'] = implode(";", $from);
        $options['to'] = implode(";", $to);
        $ret = $this->httpGet(self::MATRIX_DRIVE_DISTANCE, $options);

        $data = [];
        foreach ($ret['result']['rows'] as $row) {
            $tmp = [];
            foreach ($row['elements'] as $item) {
                $tmp[] = ["distance" => $item["distance"], "duration" => $item["duration"]];
            }
            $data[] = $tmp;
        }

        return $data;
    }

    /**
     * 根据起点坐标和终点坐标测距离 【网上随便抄的代码】
     * @param  [array]   $from 	[起点坐标(经纬度),例如:array(118.012951,36.810024)]
     * @param  [array]   $to 	[终点坐标(经纬度)]
     * @param  [bool]    $km        是否以公里为单位 false:米 true:公里(千米)
     * @param  [int]     $decimal   精度 保留小数位数
     * @return [string]  距离数值
     */
    public function getDistance($from, $to, $km = true, $decimal = 2)
    {
        sort($from);
        sort($to);
        $EARTH_RADIUS = 6370.996;

        $distance = $EARTH_RADIUS * 2 * asin(sqrt(pow(sin(($from[0] * pi() / 180 - $to[0] * pi() / 180) / 2), 2) + cos($from[0] * pi() / 180) * cos($to[0] * pi() / 180) * pow(sin(($from[1] * pi() / 180 - $to[1] * pi() / 180) / 2), 2))) * 1000;

        if ($km) {
            $distance = $distance / 1000;
        }

        return round($distance, $decimal);
    }

    /**
     * @param $url
     * @param $params
     * @return mixed
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function httpGet($url, $params)
    {
        $mapKey = get_setting_values('store', 'map_key');
        if ($mapKey) {
            $params["key"] = $mapKey;

            $url .= '?' . http_build_query($params);
            $response = $this->client->get($url);
            $ret = json_decode($response->getBody(), true);
            if ($ret['status'] === 0) {
                return $ret;
            } else {
                throw new MapException("MAP API ERROR:{$ret['message']}");
            }
        } else {
            \Log::info("请输入已选择的MAP KEY");
            throw new MapException("请输入已选择的MAP KEY");
        }


    }
}
